import type { RouteLocationNormalized } from 'vue-router'
import type {
  AxiosRequestConfigExtendType,
  KeepPageStore,
} from '@/types'

/**
 * 不支持页面缓存的规则
 */
const excludeRules = [/^\/.[^\n\r?\u2028\u2029]*\?.[^\n\r=\u2028\u2029]*=.+$/]
type KeyType = string | RegExp | (string | RegExp)[]
function handleExclude(target: string, key: string | RegExp) {
  if (key instanceof RegExp) {
    return key.test(target)
  }
  else {
    return target === key
  }
}
function isExclude(target: string, key: KeyType) {
  if (Verify.isArray(key)) {
    return (key as (string | RegExp)[]).some(s =>
      handleExclude(target, s),
    )
  }
  return handleExclude(target, key as string | RegExp)
}

/** 页面缓存数据仓库 */
export const useKeepPageStore = defineStore(
  'keepPageStore',
  {
    state: (): KeepPageStore => ({
      history: [],
      enabled: true,
      includePages: [],
      excludePages: [],
      scrollTop: 0,
      keepMax: 10,
      destructionSequence: [],
    }),
    getters: {},
    actions: {
      /** 添加历史记录 */
      pushHistory(path: string) {
        if (!this.enabled)
          return
        if (this.history.length > this.keepMax) {
          this.history.shift()
        }
        this.history.push(path)
        // console.log('查看路由历史：', this.history);
      },
      /** 更改最大缓存数 */
      changeKeepMax(step = -1) {
        this.keepMax += step
        if (step >= 0)
          return
        // ! 处理减少的情况
        step = Math.abs(step)

        for (const _ of range(step)) {
          this.remove()
        }
      },
      has(key: string) {
        return this.includePages.includes(key)
      },
      /**
       * 排除不缓存的页面
       * @param key 当前页面路径
       * @description 返回一个函数且执行一次
       */
      exclude(key?: string) {
        if (!key) {
          const { path } = useRoute()
          key = path
        }
        if (this.excludePages.includes(key!))
          return
        this.excludePages.push(key!)
      },
      /**
       * 当跳转到目标路径时，该页面当次取消缓存
       * @param key 目标路径,全匹配(/*)
       */
      to(key: KeyType) {
        if (!this.enabled)
          return
        const { path } = useRoute()
        if (this.excludePages.includes(path))
          return
        onBeforeRouteLeave(
          (
            to: RouteLocationNormalized,
            form: RouteLocationNormalized,
          ) => {
            const isE = isExclude(to.path, key)
            if (!isE)
              return
            this.remove(form.path)
          },
        )
      },
      /**
       * 当从目标路径跳转过来，该页面当次取消缓存
       * @param key 从目录路径跳转过来,全匹配(/*)
       * @param isRefresh 当key值命中时是否刷新页面否则将会在下次页面进入时刷新,默认开启
       */
      form(key: KeyType, isRefresh = true) {
        if (!this.enabled)
          return

        const { currentRoute } = useRouter()
        if (
          this.excludePages.includes(
            currentRoute.value.path,
          )
        ) {
          return
        }
        const { refresh } = useGlobalStore()
        onActivated(async () => {
          await nextTick()
          // ! 对于可能携带路径参数等的重新加载
          const isValid = excludeRules.some(reg =>
            reg.test(currentRoute.value.fullPath),
          )
          await nextTick()
          if (isValid) {
            // if (!this.has(history.current)) return;
            refresh()
            return
          }
          // 查询跳转前的路径
          const prevPath = this.history?.at?.(-2)
          if (!prevPath)
            return
          const isE = isExclude(prevPath, key)

          if (!isE)
            return
          await nextTick()
          if (isRefresh) {
            refresh()
          }
          else {
            this.remove(currentRoute.value.path)
          }
        })
      },
      /**
       * to、form 函数的合集
       * @param isRefresh 当key值命中时是否刷新页面否则将会在下次页面进入时刷新
       * @description 内部直接调用to、form函数并做一些兼容处理
       */
      formTo(
        toKey: KeyType,
        formKey: KeyType,
        isRefresh = true,
      ) {
        if (!this.enabled)
          return
        const { path } = useRoute()
        if (this.excludePages.includes(path))
          return
        this.to(toKey)
        this.form(formKey, isRefresh)
      },
      /**
       * 处理当前页面请求未全部完成的情况
       */
      abort(ajaxConfig: AxiosRequestConfigExtendType) {
        if (!this.enabled || !ajaxConfig.requestPage)
          return
        if (
          this.excludePages.includes(ajaxConfig.requestPage)
        )
          return
        this.remove(ajaxConfig.requestPage)
        console.warn('发送错误')
      },
      /** 清除缓存 */
      clearCache() {
        if (!this.enabled)
          return
        if (this.includePages.length > 0) {
          ElMessage.success('清除缓存成功！')
        }
        this.includePages.length = 0
        this.destructionSequence.length = 0
      },
      add(key: string) {
        if (
          !this.enabled
          || this.excludePages.includes(key)
        ) {
          return
        }
        const isValid = excludeRules.some(reg =>
          reg.test(key),
        )
        if (isValid)
          return
        const isOverflow
          = this.includePages.length === this.keepMax

        // !判断是否存在
        const isPresence = this.includePages.includes(key)
        // console.log(
        //   '新增：',
        //   key,
        //   isValid,
        //   isPresence,
        //   this.includePages,
        //   this.destructionSequence
        // );
        // !更新状态为活跃=>
        if (isPresence) {
          this.active(key)
          isOverflow && this.remove()
          return
        }
        // !超过最大数量，移除最久未使用
        isOverflow && this.remove()

        this.destructionSequence.push({
          key,
          active: 1,
        })
        this.includePages.push(key)
      },
      remove(key?: string) {
        if (!this.enabled)
          return
        if (!key) {
          // 查找最久、最不活跃
          key = this.findLazinessKey()
        }
        if (this.excludePages.includes(key))
          return
        const index = this.includePages.indexOf(key)
        // 指定key
        // console.log(
        //   'remove',
        //   key,
        //   this.includePages,
        //   index
        // );

        this.includePages.splice(index, 1)
        // ! 查找关系位置
        const _index = this.destructionSequence.findIndex(
          item => item.key === key,
        )
        // console.log(
        //   'remove _index',
        //   this.destructionSequence,
        //   _index
        // );
        this.destructionSequence.splice(_index, 1)
      },
      removeOther(key: string) {
        if (
          !this.enabled
          || this.excludePages.includes(key)
        ) {
          return
        }
        const index = this.includePages.indexOf(key)
        // !移除其他，仅保留自身
        this.includePages.splice(index + 1, this.keepMax)
        this.includePages.splice(0, index)
        // console.log(this.includePages, m);

        this.destructionSequence.length = 0
        this.destructionSequence.push({
          key,
          active: 1,
        })
      },
      active(key: string) {
        if (
          !this.enabled
          || this.excludePages.includes(key)
        ) {
          return
        }
        const m = this.destructionSequence.find(
          item => item.key === key,
        )
        // console.log(
        //   this.includePages,
        //   this.destructionSequence,
        //   key,
        //   index,
        //   m
        // );

        m!.active += 1
      },
      /** 查找最懒惰的页面 */
      findLazinessKey() {
        if (!this.enabled)
          return ''
        const m = this.destructionSequence.sort(
          (a, b) => a.active - b.active,
        )
        const index = m[0]?.key ?? ''
        return index
      },
    },
    persist: {
      key: 'sysinteg_keep_page',
    },
  },
)
